//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2003 Intrinsyc Europe Ltd.
//////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2004 Siemens AG
//
// Version: 1.1.2.5
// Date:    11. Jan. 2006
//////////////////////////////////////////////////////////////////////////////
//
//
// (C) Copyright 2007 Marvell International Ltd.
//  All Rights Reserved
//


#include "precomp.h"

BOOL g_fAudioProfDownload = TRUE;

// The audio configuration (defaults)
AUDIO_CONFIG g_acAudioConfig[MAX_AUDIO_MODES] = {
    // RIL_AUDIO_NONE
    {
        1,                                          // Audio mode setting for modem
        0,                                          // BbcGain
        0, 0, 0, 0, 0, 0,                       // SideToneSteps
        0,                                         // Interface (Analog/Digital)
        0,                                         // Microphone
        0,                                         // Earpiece
        32000, 32000, 32000, 32000, 32000, 32000,   // Tx AC steps
        5500, 8000, 11000, 16000, 24000, 32000,     // Rx AC steps
        32767, 32767, 32767, 32767, 32767, 32767,   // Tx MC steps
        2800, 4000, 5500, 8000, 11000, 16000        // Rx MC steps
    },
    // RIL_AUDIO_HANDSET
    {
        5,   //4,
        0,
        0, 0, 0, 0, 0, 0,
        1,   //0,
        1,   //0,
        1,   //0,
        32000, 32000, 32000, 32000, 32000, 32000,
        5500, 8000, 11000, 16000, 24000, 32000,
        32767, 32767, 32767, 32767, 32767, 32767,
        2800, 4000, 5500, 8000, 11000, 16000
    },
    // RIL_AUDIO_SPEAKERPHONE
    {
        2,
        0,
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        32000, 32000, 32000, 32000, 32000, 32000,
        5500, 8000, 11000, 16000, 24000, 32000,
        32767, 32767, 32767, 32767, 32767, 32767,
        2800, 4000, 5500, 8000, 11000, 16000
    },
    // RIL_AUDIO_HEADSET
    {
        3,
        0,
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        32000, 32000, 32000, 32000, 32000, 32000,
        5500, 8000, 11000, 16000, 24000, 32000,
        32767, 32767, 32767, 32767, 32767, 32767,
        2800, 4000, 5500, 8000, 11000, 16000
    },
    // RIL_AUDIO_CARKIT
    {
        2,
        0,
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        32000, 32000, 32000, 32000, 32000, 32000,
        5500, 8000, 11000, 16000, 24000, 32000,
        32767, 32767, 32767, 32767, 32767, 32767,
        2800, 4000, 5500, 8000, 11000, 16000
    },
    // RIL_AUDIO_SIEMENS_BLUETOOTHHEADSET
    {
        3,
        0,
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        32000, 32000, 32000, 32000, 32000, 32000,
        5500, 8000, 11000, 16000, 24000, 32000,
        32767, 32767, 32767, 32767, 32767, 32767,
        2800, 4000, 5500, 8000, 11000, 16000
    },
    // RIL_AUDIO_SIEMENS_BLUETOOTHCARKIT
    {
        2,
        0,
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        32000, 32000, 32000, 32000, 32000, 32000,
        5500, 8000, 11000, 16000, 24000, 32000,
        32767, 32767, 32767, 32767, 32767, 32767,
        2800, 4000, 5500, 8000, 11000, 16000
    },
    // RIL_AUDIO_SIEMENS_GENERIC1
    {
        4,
        0,
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        32000, 32000, 32000, 32000, 32000, 32000,
        5500, 8000, 11000, 16000, 24000, 32000,
        32767, 32767, 32767, 32767, 32767, 32767,
        2800, 4000, 5500, 8000, 11000, 16000
    },
    // RIL_AUDIO_SIEMENS_GENERIC2
    {
        2,
        0,
        0, 0, 0, 0, 0, 0,
        0,
        0,
        0,
        32000, 32000, 32000, 32000, 32000, 32000,
        5501, 8001, 11001, 16001, 24001, 32001,
        32767, 32767, 32767, 32767, 32767, 32767,
        2801, 4001, 5501, 8001, 11001, 16001
    }
};

int g_iAudioTable[MAX_AUDIO_MODES] = {  RIL_AUDIO_NONE,
                                                                RIL_AUDIO_HANDSET,
                                                                RIL_AUDIO_SPEAKERPHONE,
                                                                RIL_AUDIO_HEADSET,
                                                                RIL_AUDIO_CARKIT,
                                                                RIL_AUDIO_SIEMENS_BLUETOOTHHEADSET,
                                                                RIL_AUDIO_SIEMENS_BLUETOOTHCARKIT,
                                                                RIL_AUDIO_SIEMENS_GENERIC1,
                                                                RIL_AUDIO_SIEMENS_GENERIC2};
                                                                

TCHAR *g_szAudioRegKeyTable[MAX_AUDIO_MODES] = { TEXT(""),      // No registry key for RIL_AUDIO_NONE
                        RIL_AUDIO_CONFIG_HANDSET,
                        RIL_AUDIO_CONFIG_SPEAKERPHONE,
                        RIL_AUDIO_CONFIG_HEADSET,
                        RIL_AUDIO_CONFIG_CARKIT,
                        RIL_AUDIO_CONFIG_SIEMENS_BLUETOOTHHEADSET,
                        RIL_AUDIO_CONFIG_SIEMENS_BLUETOOTHCARKIT,
                        RIL_AUDIO_CONFIG_SIEMENS_GENERIC1,
                        RIL_AUDIO_CONFIG_SIEMENS_GENERIC2};

int GetAudioTableIndex(int iAudioMode)
{
    int iIndex = 0;

    for (int i=0; i < MAX_AUDIO_MODES; i++)
    {
        if (g_iAudioTable[i] == iAudioMode)
        {
            iIndex = i;
            break;
        }
    }

    return iIndex;
}

//
//
//
BOOL CRilHandle::ExParseSBNRResponse(char *pszATResponse, UINT uiBufLen, PDWORD pdwVersion)
{
    DWORD dwStartPos, dwEndPos;
    DWORD dwV1, dwV2, dwV3;

    TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, TEXT("RilDrv: +ExParseSBNRResponse()"));

    *pdwVersion = (DWORD)0;

    dwStartPos = 0;
    if(!FindString(dwStartPos, pszATResponse, "^SBNR: ", uiBufLen, &dwEndPos))
    {
        RILRetailTrace((TEXT("RilDrv: can't find ^SBNR\r\n")));
        return FALSE;
    }
    uiBufLen -= (dwEndPos-dwStartPos);
    dwStartPos = dwEndPos;
    dwV1 = (DWORD)atoi((char*)&pszATResponse[dwStartPos]);
    if(!FindString(dwStartPos, pszATResponse, ",", uiBufLen, &dwEndPos))
    {
        RILRetailTrace((TEXT("RilDrv: can't find comma 1\r\n")));
        return FALSE;
    }
    uiBufLen -= (dwEndPos-dwStartPos);
    dwStartPos = dwEndPos;
    dwV2 = (DWORD)atoi((char*)&pszATResponse[dwStartPos]);
    if(!FindString(dwStartPos, pszATResponse, ",", uiBufLen, &dwEndPos))
    {
        RILRetailTrace((TEXT("RilDrv: can't find comma 2\r\n")));
        return FALSE;
    }
    uiBufLen -= (dwEndPos-dwStartPos);
    dwStartPos = dwEndPos;
    dwV3 = (DWORD)atoi((char*)&pszATResponse[dwStartPos]);
    if (IS_ADI)
    {
        dwV1 &= 0xFF;
        dwV2 &= 0xFF;
        dwV3 &= 0xFF;
        *pdwVersion = dwV1<<16 | dwV2<<8 | dwV3;
    }
    else
    {
        if(!FindString(dwStartPos, pszATResponse, ",", uiBufLen, &dwEndPos))
        {
            RILRetailTrace((TEXT("RilDrv: can't find comma 3\r\n")));
            return FALSE;
        }
        uiBufLen -= (dwEndPos-dwStartPos);
        dwStartPos = dwEndPos;
        if(!FindString(dwStartPos, pszATResponse, ",", uiBufLen, &dwEndPos))
        {
            RILRetailTrace((TEXT("RilDrv: can't find comma 4\r\n")));
            return FALSE;
        }
        dwStartPos = dwEndPos;
        *pdwVersion = (DWORD)atoi((char*)&pszATResponse[dwStartPos]);
    }
    TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, TEXT("RilDrv: -ExParseSBNRResponse()"));

    return TRUE;
}

DWORD g_dwRadioAudioProfilesVersion = 0;

//
//
//
BOOL CRilHandle::CheckAudioProfilesVersion(COM_PORT_TYPE PortType)
{
    DWORD dwProfilesDLLVersion;
    const char szAudVer[] = "AT^SBNR=AUD\r";
    const char szAudVerMC75[] = "AT^SBNR=\"AUD\",1\r";
    DWORD dwTemp = 0;
    //char szResponse[64];

    TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, TEXT("RilDrv: +CheckAudioProfilesVersion()"));

    GetRegistryDWORD(RIL_AUDIO_CONFIG_ROOT, RIL_AUDIO_CONFIG_KEY, RIL_AUDIO_CONFIG_DISABLE, &dwTemp);
    if(dwTemp == 1) g_fAudioProfDownload = FALSE;

    dwTemp = 0;
    GetRegistryDWORD(RIL_AUDIO_CONFIG_ROOT, RIL_AUDIO_CONFIG_KEY, RIL_AUDIO_VERSION_CHECK_DISABLE, &dwTemp);
    if(dwTemp == 1)
        goto Error;

    AudProf_GetProfilesVersion(&dwProfilesDLLVersion);

    // Adjust version to modem format
    dwProfilesDLLVersion = ((dwProfilesDLLVersion>>8)&0xFF) + ((dwProfilesDLLVersion>>24) * 100);
    TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, TEXT("Audio profiles DLL version %d"), dwProfilesDLLVersion);

#ifdef RIL_CHECK_AUDIO_VERSION    
    if (!ExSendATCmdGetRsp(PortType, (char*)(IS_ADI?szAudVerMC75:szAudVer), szResponse, sizeof(szResponse), 20000, 1))
    {
        goto Error;
    }
    if(!ExParseSBNRResponse(szResponse, sizeof(szResponse), &g_dwRadioAudioProfilesVersion))
    {
        RILRetailTrace((TEXT("RilDrv: Unable to get audio prof version\r\n")));
        TBD_OUTPUT(TBDCT_INFO, TBDOL_ERROR, TEXT("Unable to get audio profiles version from radio"));
        goto Error;
    }


    TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, TEXT("Radio audio profiles version %d"), g_dwRadioAudioProfilesVersion);

    // The MC75 audio profile download has to be performed with the "CEAudioSwup" tool. An automated
    // update with the audioprofiles.dll is only possible with MC4x, AC45 and MC5x modules.
    if (!IS_ADI)
    {
        if(g_dwRadioAudioProfilesVersion != dwProfilesDLLVersion)
        {
            RILRetailTrace((TEXT("RilDrv: Audio profiles do not match\r\n")));
            TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, TEXT("Audio profiles do not match"));
            return TRUE;
        }
    }
#endif

Error:
    
    TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, TEXT("RilDrv: -CheckAudioProfilesVersion()\n"));
    return FALSE;
}

//
//
//
BOOL CRilHandle::DownloadAudioProfiles(COM_PORT_TYPE PortType)
{
    const char *pProfilesData;
    DWORD dwProfilesLines, dwProfilesLastLineLength;
    UCHAR ucLine, i;
    char szCmd[256];
    char szProf[100];
    char szResponse[128];
    HANDLE hAudStart, hAudEnd;
    BOOL fRet = FALSE;

    hAudStart = CreateEvent(NULL, FALSE, FALSE, RIL_AUDIO_PROF_START);
    hAudEnd = CreateEvent(NULL, FALSE, FALSE, RIL_AUDIO_PROF_END);

    if(g_fAudioProfDownload)
    {
        // Fetch the info from the profiles DLL
        AudProf_GetProfilesData(&pProfilesData);
        AudProf_GetProfilesLines(&dwProfilesLines);
        AudProf_GetProfilesLastLineLength(&dwProfilesLastLineLength);

        TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, TEXT("Audio profiles lines = %d"), dwProfilesLines);

        SetEvent(hAudStart);
        for(ucLine=1; ucLine<=dwProfilesLines; ucLine++)
        {
            for(i=0;i<80;i++)szProf[i] = *pProfilesData++;
            szProf[i] = '\0';   // Null terminate the string

            // The last line can be shorter than the rest so terminate it at the correct place
            if(ucLine == dwProfilesLines)szProf[dwProfilesLastLineLength] = '\0';

            sprintf(szCmd, "AT^SBNW=AUD,0,%d,%d\r", ucLine, dwProfilesLines);
            if (!ExSendATCommand(PortType, szCmd))
            {
                goto Error;
            }
            Sleep(500);
            sprintf(szCmd, "%s\x1a", szProf);
            if (!ExSendATCommand(PortType, szCmd))
            {
                goto Error;
            }
            Sleep(200);
            if (!ExGetATResponse(PortType, szResponse, sizeof(szResponse), 20000))
            {
                goto Error;
            }
        }
        SetEvent(hAudEnd);
    }
    else
    {
        RILRetailTrace((TEXT("RilDrv: Audio profile download is disabled\r\n")));
    }

    fRet = TRUE;

Error:
    CloseHandle(hAudStart);
    CloseHandle(hAudEnd);

    return fRet;
}

void FillEmptyAudioSteps(DWORD *pdwSteps, DWORD dwMaxSteps, DWORD dwNumSteps)
{
    // For the TxMcSteps and TxAcSteps the user ist not requiered to fill in all registry values.
    // In this case the rest of the array is filled with the last given value.

    if (dwNumSteps < dwMaxSteps && dwNumSteps > 0)
    {
        UINT i;

        for (i=dwNumSteps; i<dwMaxSteps;i++)
            pdwSteps[i] = pdwSteps[i-1];
    }
}

//
//
//
void GetAudioConfig(void)
{
    INT iAudioMode;
    HKEY    hKey = NULL;
    DWORD   dwSize, dwTemp;

    TBD_OUTPUT(TBDCT_INFO, TBDOL_INFORMATION, TEXT("+GetAudioConfig()"));

    // fetch all audiomode (expect RIL_AUDIO_NONE)
    for (iAudioMode = 1; iAudioMode < MAX_AUDIO_MODES; iAudioMode++)
    {
        GetRegistryDWORD(RIL_AUDIO_CONFIG_ROOT, g_szAudioRegKeyTable[iAudioMode], RIL_AUDIO_CONFIG_MODE, &(g_acAudioConfig[iAudioMode].dwAudioMode));
        GetRegistryDWORD(RIL_AUDIO_CONFIG_ROOT, g_szAudioRegKeyTable[iAudioMode], RIL_AUDIO_CONFIG_GAIN, &(g_acAudioConfig[iAudioMode].dwGain));
        GetRegistryDWORD(RIL_AUDIO_CONFIG_ROOT, g_szAudioRegKeyTable[iAudioMode], RIL_AUDIO_CONFIG_SIDETONE, &(g_acAudioConfig[iAudioMode].dwSideToneSteps[0]));
        for (int iIdx=1; iIdx < MAX_VOLUME_STEPS; iIdx++)
            g_acAudioConfig[iAudioMode].dwSideToneSteps[iIdx] = g_acAudioConfig[iAudioMode].dwSideToneSteps[0];
        GetRegistryDWORD(RIL_AUDIO_CONFIG_ROOT, g_szAudioRegKeyTable[iAudioMode], RIL_AUDIO_CONFIG_INTERFACE, &(g_acAudioConfig[iAudioMode].dwInterface));
        GetRegistryDWORD(RIL_AUDIO_CONFIG_ROOT, g_szAudioRegKeyTable[iAudioMode], RIL_AUDIO_CONFIG_MICROPHONE, &(g_acAudioConfig[iAudioMode].dwMicrophone));
        GetRegistryDWORD(RIL_AUDIO_CONFIG_ROOT, g_szAudioRegKeyTable[iAudioMode], RIL_AUDIO_CONFIG_EARPIECE, &(g_acAudioConfig[iAudioMode].dwEarpiece));
        RegOpenKeyEx(RIL_AUDIO_CONFIG_ROOT, g_szAudioRegKeyTable[iAudioMode], 0, 0, &hKey);
        if(hKey != NULL) {
            dwSize = MAX_VOLUME_STEPS*sizeof(DWORD);
            RegQueryValueEx(hKey, RIL_AUDIO_CONFIG_TXACSTEPS, 0, 0, (UCHAR*)&(g_acAudioConfig[iAudioMode].dwTxAcSteps[0]), &dwSize);
            FillEmptyAudioSteps(g_acAudioConfig[iAudioMode].dwTxAcSteps, MAX_VOLUME_STEPS, dwSize/sizeof(DWORD));
            dwSize = MAX_VOLUME_STEPS*sizeof(DWORD);
            RegQueryValueEx(hKey, RIL_AUDIO_CONFIG_RXACSTEPS, 0, 0, (UCHAR*)&(g_acAudioConfig[iAudioMode].dwRxAcSteps[0]), &dwSize);
            dwSize = MAX_VOLUME_STEPS*sizeof(DWORD);
            RegQueryValueEx(hKey, RIL_AUDIO_CONFIG_TXMCSTEPS, 0, 0, (UCHAR*)&(g_acAudioConfig[iAudioMode].dwTxMcSteps[0]), &dwSize);
            FillEmptyAudioSteps(g_acAudioConfig[iAudioMode].dwTxMcSteps, MAX_VOLUME_STEPS, dwSize/sizeof(DWORD));
            dwSize = MAX_VOLUME_STEPS*sizeof(DWORD);
            RegQueryValueEx(hKey, RIL_AUDIO_CONFIG_RXMCSTEPS, 0, 0, (UCHAR*)&(g_acAudioConfig[iAudioMode].dwRxMcSteps[0]), &dwSize);
            dwSize = MAX_VOLUME_STEPS*sizeof(DWORD);
            RegQueryValueEx(hKey, RIL_AUDIO_CONFIG_SIDETONESTEPS, 0, 0, (UCHAR*)&(g_acAudioConfig[iAudioMode].dwSideToneSteps[0]), &dwSize);
            dwSize = MAX_VOLUME_STEPS*sizeof(DWORD);
            RegCloseKey(hKey);
        }
    }
    // Fetch the download setting
    GetRegistryDWORD(RIL_AUDIO_CONFIG_ROOT, RIL_AUDIO_CONFIG_KEY, RIL_AUDIO_CONFIG_DISABLE, &dwTemp);
    if(dwTemp == 1)g_fAudioProfDownload = FALSE;

    
}


